﻿using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;

using SimbaRGVMonitor.Models;
using SimbaRGVMonitor.Controllers;

namespace SimbaRGVMonitor.Views
{
    partial class MonitorSchedulePanel : UserControl
    {
        public MonitorSchedulePanel()
        {
            InitializeComponent();
            InitializeSettings();
        }

        //====================================================================================================
        //以上是类型构造函数
        //----------------------------------------------------------------------------------------------------
        //以下是类型字段
        //====================================================================================================

        private readonly ScheduleModel model = new ScheduleModel();
        private readonly ScheduleController controller = new ScheduleController();

        //====================================================================================================
        //以上是类型字段
        //----------------------------------------------------------------------------------------------------
        //以下是初始化设置
        //====================================================================================================

        private void InitializeSettings()
        {
            scheduleCanvas.MapTop = 50;
            scheduleCanvas.MapLeft = 50;
            scheduleCanvas.MapVRate = 1;
            scheduleCanvas.MapHRate = 1;

            scheduleCanvas.Loaded += WhenCanvasLoaded;
            scheduleCanvas.Unloaded += WhenCanvasUnLoaded;

            controller.PathsUpdated += WhenPathsUpdated;
            controller.RobotsUpdated += WhenRobotsUpdated;
            controller.VertexesUpdated += WhenVertexesUpdated;
        }

        //====================================================================================================
        //以上是初始化设置
        //----------------------------------------------------------------------------------------------------
        //以下是界面事件侦听
        //====================================================================================================

        private void WhenCanvasLoaded(object sender, RoutedEventArgs e)
        {
            model.PathAdded += WhenPathAdded;
            model.PathUpdated += WhenPathUpdated;
            model.PathRemoved += WhenPathRemoved;

            model.RobotAdded += WhenRobotAdded;
            model.RobotUpdated += WhenRobotUpdated;

            model.VertexAdded += WhenVertexAdded;
            model.VertexUpdated += WhenVertexUpdated;
            model.VertexRemoved += WhenVertexRemoved;

            var paths = model.Paths.Values;
            var robots = model.Robots.Values;
            var vertexes = model.Vertexes.Values;

            scheduleCanvas.ResetVertexes(vertexes);
            scheduleCanvas.ResetRobots(robots);
            scheduleCanvas.ResetPaths(paths);

            controller.Start();
        }

        private void WhenCanvasUnLoaded(object sender, RoutedEventArgs e)
        {
            controller.Stop();

            model.PathAdded -= WhenPathAdded;
            model.PathUpdated -= WhenPathUpdated;
            model.PathRemoved -= WhenPathRemoved;

            model.RobotAdded -= WhenRobotAdded;
            model.RobotUpdated -= WhenRobotUpdated;

            model.VertexAdded -= WhenVertexAdded;
            model.VertexUpdated -= WhenVertexUpdated;
            model.VertexRemoved -= WhenVertexRemoved;
        }

        //====================================================================================================
        //以上是界面事件侦听
        //----------------------------------------------------------------------------------------------------
        //以下是控制器事件侦听
        //====================================================================================================

        private void WhenPathsUpdated(object sender, SchedulerItemsUpdatedEventArgs<Path> e)
        {
            var paths = e.Items.ToArray();
            model.UpdatePaths(paths);
        }

        private void WhenRobotsUpdated(object sender, SchedulerItemsUpdatedEventArgs<Robot> e)
        {
            var robots = e.Items.ToArray();
            foreach(var robot in robots)
            {
                var robotNo = robot.RobotNo;
                if(model.Robots.ContainsKey(robotNo) == false)
                {
                    model.AddRobot(robot);
                }
                else
                {
                    model.UpdateRobot(robot);
                }
            }
        }

        private void WhenVertexesUpdated(object sender, SchedulerItemsUpdatedEventArgs<Vertex> e)
        {
            var vertexes = e.Items.ToArray();

            CalculateCanvasOffset(vertexes);
            model.UpdateVertexes(vertexes);
        }

        //====================================================================================================
        //以上是界控制器事件侦听
        //----------------------------------------------------------------------------------------------------
        //以下是模型事件侦听
        //====================================================================================================

        private void WhenPathAdded(object sender, PathEventArgs e)
        {
            Dispatcher.Invoke(() => scheduleCanvas.AddPath(e.Value));
        }

        private void WhenPathUpdated(object sender, PathEventArgs e)
        {
            Dispatcher.Invoke(() => scheduleCanvas.UpdatePath(e.Value));
        }

        private void WhenPathRemoved(object sender, PathEventArgs e)
        {
            Dispatcher.Invoke(() => scheduleCanvas.RemovePath(e.Key));
        }

        private void WhenRobotAdded(object sender, RobotEventArgs e)
        {
            Dispatcher.Invoke(() => scheduleCanvas.UpdateRobot(e.Value));
        }

        private void WhenRobotUpdated(object sender, RobotEventArgs e)
        {
            Dispatcher.Invoke(() => scheduleCanvas.UpdateRobot(e.Value));
        }

        private void WhenVertexAdded(object sender, VertexEventArgs e)
        {
            Dispatcher.Invoke(() => scheduleCanvas.AddVertex(e.Value));
        }

        private void WhenVertexUpdated(object sender, VertexEventArgs e)
        {
            Dispatcher.Invoke(() => scheduleCanvas.UpdateVertex(e.Value));
        }

        private void WhenVertexRemoved(object sender, VertexEventArgs e)
        {
            Dispatcher.Invoke(() => scheduleCanvas.RemoveVertex(e.Key));
        }

        //====================================================================================================
        //以上是模型事件侦听
        //----------------------------------------------------------------------------------------------------
        //以下是计算画布偏移量
        //====================================================================================================

        private void CalculateCanvasOffset(Vertex[] vertexes)
        {
            Rect canvasBounds;
            var location = new Point(0, 0);
            if (scheduleCanvas.TryGetActualBounds(location, out canvasBounds) == false)
            {
                return;
            }
            
            canvasBounds.Inflate(-1 * scheduleCanvas.MapLeft, -1 * scheduleCanvas.MapTop);

            Rect vertexesNounds;
            {
                var width = vertexes.Length == 0 ? 1 : vertexes.Select(item => item.PositionX).Max();
                var height = vertexes.Length == 0 ? 1 : vertexes.Select(item => item.PositionY).Max();
                var size = new Size { Width = width, Height = height };
                vertexesNounds = new Rect { Location = location, Size = size };
            }

            scheduleCanvas.MapHRate = Math.Max(1, canvasBounds.Width / vertexesNounds.Width);
            scheduleCanvas.MapVRate = Math.Max(1, canvasBounds.Height / vertexesNounds.Height);
        }
    }
}
